import json
import re

from django.utils import timezone
from django.shortcuts import render
from django.views import View
from django.http import JsonResponse
from django.contrib.auth import login, authenticate, logout
from django.db.models import Q
from django.conf import settings

from django_redis import get_redis_connection

from users.models import User, Address
from goods.models import SKU, GoodsVisitCount

from meiduo_mall.utils.logger import logger
from celery_tasks.email.tasks import send_verify_email
from .utils import generate_verify_email_url


# 用户中心接口  ---> 只有用户登录才能访问
# 使用扩展类对视图额外新增一个功能 ---> 判断用户是否登录
# 当一个类继承自LoginRequiredMixin 后，仅当用户登录才会执行视图函数，否则返回错误响应
# from django.contrib.auth.mixins import LoginRequiredMixin
from meiduo_mall.utils.views import LoginRequiredJSONMixin


class UserInfoView(LoginRequiredJSONMixin, View):
    """用户中心接口"""

    def get(self, request):

        # 判断用户是否已经登录
        # user.is_authenticated = True -----> 用户已登录，user是用户模型对象
        # user.is_authenticated = False ----> 用户未登录，是匿名用户模型类对象
        user = request.user

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'info_data': {
                'username': user.username,
                'mobile': user.mobile,
                'email': user.email,
                'email_active': user.email_active,
            }
        })

        # # 通过user对象判断是否登录
        # if user.is_authenticated:
        #     # 已经登录
        #     return JsonResponse({
        #         'code': 0,
        #         'errmsg': 'ok',
        #         'info_data': {
        #             'username': user.username,
        #             'mobile': user.mobile,
        #             'email': user.email,
        #             'email_active': True,
        #         }
        #     })
        # else:
        #     return JsonResponse({'code': 400, 'errmsg': '用户未登录'}, status=400, json_dumps_params={'ensure_ascii': False})


# 用户注册接口
class RegisterView(View):

    def post(self, request):
        # 1. 提取参数
        # request.body ---> b"{'username': 'zrh'.....}"
        json_str = request.body.decode()
        data = json.loads(json_str)

        username = data.get('username')
        password = data.get('password')
        password2 = data.get('password2')
        mobile = data.get('mobile')
        sms_code = data.get('sms_code')

        allow = data.get('allow', False)  # 非必传

        # 2. 校验参数
        # 2.1 必要性校验
        if not all((username, password, password2, mobile, sms_code)):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, json_dumps_params={'ensure_ascii': False})

        # 2.2 约束性校验
        if not allow:
            return JsonResponse({'code': 400, 'errmsg': '请勾选同意用户协议'}, json_dumps_params={'ensure_ascii': False})

        # 判断用户名是否重复（postman测试用，前端请求注册接口前会调用判断是否重复接口）
        if User.objects.filter(username=username):
            return JsonResponse({'code': 400, 'errmsg': '用户名已存在'}, json_dumps_params={'ensure_ascii': False})

        # 判断手机号是否重复（postman测试用，前端请求注册接口前会调用判断是否重复接口）
        if User.objects.filter(mobile=mobile):
            return JsonResponse({'code': 400, 'errmsg': '该手机号已注册'}, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400, 'errmsg': '用户名格式有误'}, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '手机号格式有误'}, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': '密码格式有误'}, json_dumps_params={'ensure_ascii': False})

        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '两次密码输入不一致'}, json_dumps_params={'ensure_ascii': False})

        # 2.3 业务性校验：短信验证码等
        # TODO: 此处将来填充校验短信验证码逻辑代码
        # 判断短信验证码是否正确：跟图形验证码的验证一样的逻辑
        # 提取服务端存储的短信验证码：以前怎么存储，现在就怎么提取
        conn = get_redis_connection('verify_code')
        sms_code_server = conn.get(f'sms_{mobile}')  # bytes

        if not sms_code_server:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码失效'}, json_dumps_params={'ensure_ascii': False})

        if sms_code != sms_code_server.decode():
            return JsonResponse({'code': 400, 'errmsg': '短信验证码有误'}, json_dumps_params={'ensure_ascii': False})

        # 3. 业务数据处理：新建用户模型类对象保存数据库、用户状态保持
        try:
            # user = User.objects.create() ---> 不加密密码
            # user = User.objects.create_user() ---> 加密密码
            # user = User.objects.create_superuser() ---> 加密密码, 超级管理员 （必须传邮箱）
            user = User.objects.create_user(
                username=username,
                password=password,
                mobile=mobile
            )
        except Exception as e:
            logger.error('注册用户，写入mysql失败')
            return JsonResponse({'code': 400, 'errmsg': '服务器繁忙，请稍后注册'}, json_dumps_params={'ensure_ascii': False})

        # TODO: 用户状态保持：把用户数据写入Session,用于下一次请求验证用户身份
        # login() ---> 1. 用户信息写入session  2. 在响应中添加Sessionid记录在cookie中
        login(request, user)

        # TODO：在cookie中设置Username记录登录的用户名作前端页面的展示
        response = JsonResponse({'code': 0, 'errmsg': 'ok'}, json_dumps_params={'ensure_ascii': False})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 14)

        # 4. 构建响应
        return response


# 用户登录接口
class LoginView(View):

    def post(self, request):
        # 1. 提取参数
        data = json.loads(request.body.decode())
        username = data.get('username')
        password = data.get('password')
        remembered = data.get('remembered', False)

        # 2. 校验参数
        if not all([username, password]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400, 'errmsg': '用户名格式有误'}, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': '密码格式有误'}, json_dumps_params={'ensure_ascii': False})

        # 3. TODO：传统登录业务处理： 根据用户填写的“用户名”和‘密码’校验
        # 3.1 根据“用户名”查询用户模型类对象：user or None
        # try:
        #     # get函数根据字段过滤出“唯一”对象，找不到抛出DoesNotExist异常
        #     # user = User.objects.get(username=username)
        #     # TODO： 多账号实现:可用手机号、用户名登录
        #     user = User.objects.get(Q(username=username) | Q(mobile=username))
        # except User.DoesNotExist as e:
        #     return JsonResponse({'code': 400, 'errmsg': '用户名或密码错误'}, json_dumps_params={'ensure_ascii': False})
        #
        # # 3.2 验证密码
        # if not user.check_password(password):
        #     return JsonResponse({'code': 400, 'errmsg': '用户名或密码错误'}, json_dumps_params={'ensure_ascii': False})

        # TODO: 多账号实现方案一   ---> 弊端： 如果用户名是手机号格式，则有问题，不建议使用
        # 默认认证后端使用字段username过滤, 可以通过User.USERNAME_FIELD来控制过滤字段
        # (1) 判断如果前端传来的usernam变量是手机号，就需要把User.USERNAME_FIELD设置为mobile
        # if re.match(r'^1[3-9]\d{9}$', username):
        #     User.USERNAME_FIELD = 'mobile'

        # TODO：多账号实现方案二   ---> users.utils 重置ModelBackend

        # 3. TODO：django内置登录处理方法: 全局认证函数：authenticate
        # 功能： 根据username和password校验用户 --- 只支持用户名校验（不支持多账号）
        # 返回值：校验成功返回用户对象，校验失败返回None
        user = authenticate(request, username=username, password=password)
        if user is None:
            return JsonResponse({'code': 400, 'errmsg': '用户名或密码错误'}, json_dumps_params={'ensure_ascii': False})

        # 状态保持
        login(request, user)

        response = JsonResponse({'code': 0, 'errmsg': 'ok'}, json_dumps_params={'ensure_ascii': False})

        # TODO： 判断是否记住用户信息
        if remembered:
            # 用户勾选了，长期状态保持
            request.session.set_expiry(None)  # 参数为None，表示该用户session数据记录2周有效期

            # TODO：在cookie中设置Username记录登录的用户名作前端页面的展示
            response.set_cookie('username', user.username, max_age=3600 * 24 * 14)
        else:
            # 用户未勾选，短期状态保持，用户关闭浏览器后失效
            request.session.set_expiry(0)  # 设置为0表示立即失效：关闭浏览器在请求则session用户数据失效
            response.set_cookie('username', user.username)

        # TODO: 合并购物车
        from carts.utils import merge_cart_cookie_to_redis
        merge_cart_cookie_to_redis(request, response)
        # 4. 构建响应
        return response


# 退出登录接口
class LogoutView(View):

    def delete(self, request):

        logout(request)

        response = JsonResponse({'code': 0, 'errmsg': 'ok'}, json_dumps_params={'ensure_ascii': False})
        response.delete_cookie('username')

        return response


# 判断用户名重复注册接口
class UsernameCountView(View):

    def get(self, request, username):
        # 1. 提取参数
            # username：路径参数，正则匹配

        # 2. 校验参数
            # 路径参数正则匹配，已经起到了校验作用

        # 3. 数据处理：根据username统计用户数量
        try:

            count = User.objects.filter(
                username=username
            ).count()

            # count = 1 if User.objects.filter(username=username) else 0

        except Exception as e:
            # 记录日志
            logger.info('数据库访问失败！')
            # 构建错误响应
            return JsonResponse({
                'code': 400,
                'errmsg': '数据库错误',
            }, json_dumps_params={'ensure_ascii': False})

        # 4. 构建响应
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'count': count,
        }, json_dumps_params={'ensure_ascii': False})


# 判断手机号重复注册接口
class MobileCountView(View):

    def get(self, request, mobile):

        try:
            count = User.objects.filter(
                mobile=mobile
            ).count()

        except Exception as e:
            logger.info('数据库访问失败！')
            # 构建错误响应
            return JsonResponse({
                'code': 400,
                'errmsg': '数据库错误',
            }, json_dumps_params={'ensure_ascii': False}, status=400)

        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'count': count,
        }, json_dumps_params={'ensure_ascii': False})


class EmailView(LoginRequiredJSONMixin, View):
    """更新、保存邮件"""
    def put(self, request):

        # 1. 提取参数
        data = json.loads(request.body.decode())
        email = data.get('email')

        # 2. 校验参数
        if not email:
            return JsonResponse({'code': 400, 'errmsg': '缺少参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$', email):
            return JsonResponse({'code': 400, 'errmsg': '邮箱格式错误'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 3. 业务处理: 保存更新邮箱   发送验证邮件（业务性校验）
        try:
            user = request.user
            user.email = email
            user.save()
        except Exception as e:
            logger.error('数据库更新邮箱失败，错误信息： %s' % e)
            return JsonResponse({'code': 400, 'errmsg': '数据库更新邮箱失败'}, status=400, json_dumps_params={'ensure_ascii': False})

        # TODO：发送验证邮件
        # 模拟一个加密的token
        verify_url = generate_verify_email_url(request)
        send_verify_email.delay(email, verify_url)

        # 4. 构建响应
        return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})


class VerifyEmailView(View):
    """激活邮箱，验证token"""
    def put(self, request):
        # 1. 提取参数
        token = request.GET.get('token')

        # 2. 校验参数
        if not token:
            return JsonResponse({'code': 400, 'errmsg': '缺少参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 3. 业务处理 ---> 校验token有效性，激活邮箱
        from meiduo_mall.utils.secret import SecretOauth

        user_info = SecretOauth().loads(token)  # 解密

        if user_info is None:
            return JsonResponse({'code': 400, 'errmsg': '邮箱验证失败'}, status=400, json_dumps_params={'ensure_ascii': False})

        user_id = user_info.get('user_id')
        user_email = user_info.get('email')
        try:
            user = User.objects.get(pk=user_id, email=user_email, is_active=True)
        except Exception as e:
            logger.info('邮箱验证用户不存在或已注销：%s' % e)
            return JsonResponse({'code': 400, 'errmsg': '邮箱验证用户不存在或已注销'}, status=400, json_dumps_params={'ensure_ascii': False})
        else:
            user.email_active = True
            user.save()

            return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})


class CreateAddressView(LoginRequiredJSONMixin, View):
    """新增用户收货地址接口"""

    def post(self, request):

        # 1. 提取参数
        json_dict = json.loads(request.body.decode())

        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 2. 校验参数
        # 2.1 业务性校验：收货地址不能超过20个
        user = request.user
        count = user.addresses.filter(is_deleted=False).count()
        print(count)
        if count >= 20:
            return JsonResponse({'code': 400, 'errmsg': '收货地址最多设置20个'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^\w{1,20}$', receiver):
            return JsonResponse({'code': 400, 'errmsg': '收货人名称不符合格式'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '参数mobile有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return JsonResponse({'code': 400, 'errmsg': '参数tel有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400, 'errmsg': '参数email有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 3. 业务处理 --> 新建address对象保存数据库
        try:
            address = Address.objects.create(
                user=request.user,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                title=receiver,  # 新增地址接口没有传递标题，此处默认把标题设置为receiver
                receiver=receiver,
                place=place,
                mobile=mobile,
                tel=tel or '',  # 如果传递了设置为传递的值，否则设置为''
                email=email or ''
            )

            # 如果用户的default_address为空，把新增收货地址设置为用户收货地址
            # user = request.user
            if not user.default_address:
                user.default_address = address
                user.save()

        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '保存收货地址错误'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 4. 构建响应
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'address': {
                'id': address.id,
                'title': address.title,
                'receiver': address.receiver,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,
            }
        }, status=200, json_dumps_params={'ensure_ascii': False})


class AddressView(LoginRequiredJSONMixin, View):
    """展示收货地址接口"""

    def get(self, request):
        # 1. 提取参数
        user = request.user

        # 2. 校验参数
        # 3. 业务处理
        addresses_list = []

        addresses = user.addresses.filter(is_deleted=False)

        for address in addresses:
            address_dict = {
                    'id': address.id,
                    'title': address.title,
                    'receiver': address.receiver,
                    'province': address.province.name,
                    'city': address.city.name,
                    'district': address.district.name,
                    'place': address.place,
                    'mobile': address.mobile,
                    'tel': address.tel,
                    'email': address.email
                }
            if address.id == user.default_address_id:
                addresses_list.insert(0, address_dict)
            else:
                addresses_list.append(address_dict)

        print(addresses_list)

        # 4. 构建响应
        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'default_address_id': user.default_address.id,
                             'addresses': addresses_list
                             }, status=200, json_dumps_params={'ensure_ascii': False})


class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):

    def delete(self, request, address_id):

        try:
            address = Address.objects.get(pk=address_id, is_deleted=False)
            address.is_deleted = True
            address.save()

            user = request.user
            if address.id == user.default_address_id:
                # 如果当前删除的地址是用户的默认地址，把默认地址设置为用户最新增加的地址
                addreses = Address.objects.filter(user=user, is_deleted=False).order_by('-update_time')
                if addreses:
                    user.default_address = addreses[0]
                else:
                    user.default_address = None
                user.save()

        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '删除地址失败'}, status=400, json_dumps_params={'ensure_ascii': False})

        return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})

    def put(self, request, address_id):
        """更新"""
        user = request.user

        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^\w{1,20}$', receiver):
            return JsonResponse({'code': 400, 'errmsg': '收货人名称不符合格式'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '参数mobile有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return JsonResponse({'code': 400, 'errmsg': '参数tel有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400, 'errmsg': '参数email有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 业务数据处理
        json_dict.pop('province')
        json_dict.pop('city')
        json_dict.pop('district')
        Address.objects.filter(pk=address_id).update(**json_dict)

        address = Address.objects.get(pk=address_id)

        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'address': {
                                 'id': address.id,
                                 'title': address.title,
                                 'receiver': address.receiver,
                                 'province': address.province.name,
                                 'city': address.city.name,
                                 'district': address.district.name,
                                 'place': address.place,
                                 'mobile': address.mobile,
                                 'tel': address.tel,
                                 'email': address.email
                             }
                             }, status=200, json_dumps_params={'ensure_ascii': False})


class DefaultAddressView(LoginRequiredJSONMixin, View):
    """设置默认地址接口"""

    def put(self, request, address_id):

        try:
            address = Address.objects.get(pk=address_id, is_deleted=False)
            user = request.user

            user.default_address = address
            user.save()
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '设置默认地址失败'}, status=400, json_dumps_params={'ensure_ascii': False})

        return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})


class UpdateTitleAddressView(LoginRequiredJSONMixin, View):
    """修改地址标题接口"""

    def put(self, request, address_id):

        data = json.loads(request.body.decode())
        title = data.get('title')
        if not title:
            return JsonResponse({'code': 400, 'errmsg': '缺少参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^\w{1,20}$', title):
            return JsonResponse({'code': 400, 'errmsg': 'title格式有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        try:
            address = Address.objects.get(pk=address_id, is_deleted=False)
            address.title = title
            address.save()
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '设置地址标题失败'}, status=400, json_dumps_params={'ensure_ascii': False})

        return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})


class ChangePasswordView(LoginRequiredJSONMixin, View):
    """修改密码接口"""

    def put(self, request):
        data = json.loads(request.body.decode())
        old_password = data.get('old_password')
        new_password = data.get('new_password')
        new_password2 = data.get('new_password2')

        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        user = request.user
        if not user.check_password(old_password):
            return JsonResponse({'code': 400, 'errmsg': '旧密码错误'}, status=400, json_dumps_params={'ensure_ascii': False})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400, 'errmsg': '新密码格式有误'}, status=400, json_dumps_params={'ensure_ascii': False})

        if new_password != new_password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入密码不一致'}, status=400, json_dumps_params={'ensure_ascii': False})

        if old_password == new_password:
            return JsonResponse({'code': 400, 'errmsg': '新旧密码不能一致'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 业务处理 ---> 设置新密码
        try:
            user.set_password(new_password)
            user.save()
        except Exception as e:
            logger.info(e)
            return JsonResponse({'code': 400, 'errmsg': '修改密码失败'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 清除登录信息
        logout(request)

        response = JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})

        response.delete_cookie('username')

        # 返回响应，重定向到登录页面
        return response


class UserBrowseHistory(LoginRequiredJSONMixin, View):
    """用户浏览历史记录接口"""

    def get(self, request):
        """提取用户浏览历史"""
        user = request.user

        # 业务数据处理 --> 访问redis获取浏览历史，访问Mysql获取详情
        conn = get_redis_connection('history')
        sku_ids = conn.lrange(f'history_{user.id}', 0, -1)

        skus = []
        # sku_queryset = SKU.objects.filter(id__in=sku_ids)  # id__in=sku_ids --> select * from tb_skus id in (1,4,3,6)

        for sku_id in sku_ids:
            sku = SKU.objects.get(pk=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'skus': skus,
                             }, status=200, json_dumps_params={'ensure_ascii': False})

    def post(self, request):
        """保存用户浏览历史"""

        # 1. 提取参数
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')

        # 2. 校验参数
        if not sku_id:
            return JsonResponse({'code': 400, 'errmsg': '缺少必要参数'}, status=400, json_dumps_params={'ensure_ascii': False})

        try:
            sku = SKU.objects.get(pk=sku_id, is_launched=True)
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '商品无效'}, status=400, json_dumps_params={'ensure_ascii': False})

        # 3. 业务处理 --> 写入redis记录历史信息
        user = request.user
        conn = get_redis_connection('history')

        p = conn.pipeline()
        # （1） 去重
        p.lrem(f'history_{user.id}', 0, sku_id)

        # （2） 存redis浏览记录
        p.lpush(f'history_{user.id}', sku_id)  # 列表左侧插入，保证左侧最新访问

        # （3） 截取
        p.ltrim(f'history_{user.id}', 0, 4)

        p.execute()

        # TODO： 记录当前sku_id商品分类访问量
        cur_0_time = timezone.localtime().replace(hour=0, minute=0, second=0)
        category = sku.category

        try:
            visit = GoodsVisitCount.objects.get(category=category, create_time__gte=cur_0_time)

            visit.count += 1
            visit.save()
        except Exception as e:
            GoodsVisitCount.objects.create(count=1, category=category)

        # 4. 构建响应
        return JsonResponse({'code': 0, 'errmsg': 'ok'}, status=200, json_dumps_params={'ensure_ascii': False})












